#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <error.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <poll.h>

#include <openssl/aes.h>

//gcc -Wall aes_test_ll.c -o aes_test_ll -lssl -l crypto

/*
*ecb:电码本模式(优点：简单、有利于并行计算、误差不会被传送；缺点：不能隐藏明文模式、可能对明文进行主动攻击)
*cbc:密码分组链接模式(优点：不容易主动攻击、安全性比ecb好、适合传输长度长的报文；缺点：不利于并行计算、会传递误差)
*cfb:密码反馈模式(优点：隐藏了明文模式、分组密码转化为流模式、可以及时加密传送小于分组的数据；缺点：不利于并行计算、会传递误差)
*ofb:输出反馈模式(优点：隐藏了明文模式、分组密码转化为流模式、可以及时加密传送小于分组的数据；缺点：不利于并行计算、会传递误差、对明文的主动攻击是可能的)
*ctr:计算器模式
*/

int main(int argc,char *argv[])
{
    int ret = -1;
    const unsigned char cipherin[] = {"hello-word-word-hello-word-word-"};
    unsigned char cipherout[256] = {0};
    unsigned char *plainin,plainout[256] = {0};
    int num;
    unsigned char ivec[AES_BLOCK_SIZE];
    const unsigned char usr_key[] = {   0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,
                                        0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};
    AES_KEY cipherkey,plainkey;

    ret = AES_set_encrypt_key(usr_key,sizeof(usr_key) * 8,&cipherkey);
    if(ret < 0)
    {
        printf("AES_set_encrypt_key error:%d..\r\n",ret);
        return ret;
    }

    //与AES_ecb_encrypt一样，一次只能加密16个字节
    // AES_encrypt(cipherin,cipherout,&cipherkey);
    // AES_ecb_encrypt(cipherin,cipherout,&cipherkey,AES_ENCRYPT);

    memset(ivec,0,sizeof(ivec));
    // AES_cbc_encrypt(cipherin,cipherout,sizeof(cipherin),&cipherkey,ivec,AES_ENCRYPT);
    
    //实际测试，能够加密，解密失败
    num = 0;
    AES_cfb128_encrypt(cipherin,cipherout,sizeof(cipherin),&cipherkey,ivec,&num,AES_ENCRYPT);

    printf("plaintext:%s\r\n",cipherin);
    printf("ciphertext:\r\n");
    for(int i = 0;i < sizeof(cipherout);i++)
    {
        if(i && (!(i % 10)))
        {
            printf("\r\n");
        }
        printf("%02x ",cipherout[i]);
    }
    printf("\r\n");

    ret = AES_set_decrypt_key(usr_key,sizeof(usr_key) * 8,&plainkey);
    if(ret < 0)
    {
        printf("AES_set_decrypt_key error..\r\n");
        return ret;
    }

    plainin = cipherout;
    //与AES_ecb_encrypt一样
    // AES_decrypt(plainin,plainout,&plainkey);
    // AES_ecb_encrypt(plainin,plainout,&plainkey,AES_DECRYPT);

    memset(ivec,0,sizeof(ivec));
    // AES_cbc_encrypt(plainin,plainout,sizeof(plainout),&plainkey,ivec,AES_DECRYPT);
    
    //实际测试，解密失败（原因未知）
    AES_cfb128_encrypt(plainin,plainout,sizeof(cipherin),&plainkey,ivec,&num,AES_DECRYPT);

    printf("plaintext:%s\r\n",plainout);

    return 0;
}